library(here)
library(DBI)
library(RSQLite)
library(raster)
library(sf)
library(httr) # generic webservice package
library(tmap)
#NASIS tables
# pedon to siteobs: siteobsiidref==siteobsiid
pedon <- data.table::fread("C:/R_Drive/Data_Files/LPKS_Data/Data/Soil_Pedon_Databases/NRCS/NASIS/NASIS_APRIL_2017/CSV_files/pedon.csv",
sep = "|", header = T)
siteobs <- data.table::fread("C:/R_Drive/Data_Files/LPKS_Data/Data/Soil_Pedon_Databases/NRCS/NASIS/NASIS_APRIL_2017/CSV_files/siteobs.csv",
sep = "|", header = T)
nasis_pedon <- pedon |> dplyr::select(peiid, siteobsiidref, earthcovkind1, earthcovkind2, pedlabsampnum) |> dplyr::left_join(siteobs |> dplyr::select(siteobsiid, obsdate), by=c('siteobsiidref'='siteobsiid'))
#join to LT_phy_chem
LT_phy_chem_nasis <- LT_phy_chem |> dplyr::left_join(nasis_pedon, by="peiid") |> dplyr::distinct()
tmap_mode("view")
tmap mode set to interactive viewing
tm_shape(states) +
tm_borders() +
tm_lines(lwd = "strokelwd", legend.lwd.show = FALSE) +
tm_shape(LT_data_points) +
tm_dots(col="#1B9E77", size=0.3) +
#tm_scale_bar(position = c(0.06, 0.05)) +
tm_add_legend('fill',
col = c( "#1B9E77"),
border.col = "grey40",
size = 1,
labels = c('KSSL'),
title="Potential Sampling Areas") +
tm_layout(main.title = "Loamy Tableland ESD", bg.color = "white", legend.outside = TRUE) +
tm_view(set.view = c(-99.22, 39.13, 4))
LT_data_points_nlcd_data <- dplyr::bind_cols(LT_phy_chem_nasis, Lt_nlcd.df)
LT_data_points_nlcd <- LT_data_points_nlcd_data |> dplyr::filter(!is.na(texture_lab), !hzn_bot < hzn_top, !hzn_bot == hzn_top)
aqp::depths(LT_data_points_nlcd) <- pedon_key ~ hzn_top + hzn_bot
converting profile IDs from integer to character
LT_data_points_nlcd.slab.r <- aqp::slab(LT_data_points_nlcd, fm = pedon_key ~ clay_total + silt_total + sand_total + bulk_density_third_bar + ph_h2o + organic_carbon_walkley_black + estimated_organic_carbon + aggregate_stability_05_2_mm, slab.structure=c(0,15), slab.fun=mean_na)
Note: aqp::slice() will be deprecated in aqp version 2.0
--> Please consider using the more efficient aqp::dice()
LT_data_points_nlcd.slab.r.1 <- LT_data_points_nlcd.slab.r |> dplyr::select(-c(contributing_fraction)) |> tidyr::pivot_wider(names_from=variable, values_from=value)
LT_data_points_nlcd.slab.r.1[ is.na(LT_data_points_nlcd.slab.r.1) ] <- NA
LT_data_points_nlcd.slab.r.1 <- LT_data_points_nlcd.slab.r.1 |> dplyr::rowwise() |> dplyr::mutate(soc = if_else(!is.na(organic_carbon_walkley_black), organic_carbon_walkley_black, estimated_organic_carbon))|> dplyr::mutate(soc_cl = soc_class(soc), ph_cl = ph_class(ph_h2o), db_cl = db_class(bulk_density_third_bar), txt_class = gettt(sand_total, silt_total, clay_total))
LT_data_points_complete <- LT_data_points_nlcd.slab.r.1 |> dplyr::filter(!is.na(soc_cl) & !is.na(db_cl) & !is.na(ph_cl) & !is.na(txt_class)) |> dplyr::select(pedon_key, top, bottom, soc_cl, ph_cl, db_cl, txt_class) |> dplyr::ungroup() |> dplyr::mutate(pedon_key = as.integer(pedon_key))
LT_data_points_nlcd_data_sub <- LT_data_points_nlcd_data |> dplyr::select(pedon_key, SSL_name, lat, lon, earthcovkind1,obsdate,lc) |> dplyr::distinct()
LT_data_points_complete <- LT_data_points_complete |> dplyr::left_join(LT_data_points_nlcd_data_sub, by="pedon_key")
#DSP4SH database
dsp_data_points_nlcd_data <- dplyr::bind_cols(pedon_lab, dsp_nlcd.df)
aqp::depths(dsp_data_points_nlcd_data) <- pedon_ID ~ lay_depth_to_top + lay_depth_to_bottom
converting profile IDs from integer to character
dsp_data_points_nlcd.slab.r <- aqp::slab(dsp_data_points_nlcd_data, fm = pedon_ID ~ clay_tot_psa + silt_tot_psa + sand_tot_psa + Bulk_Density + ph_h2o + SOC_pct + KSSL_WSA, slab.structure=c(0,15), slab.fun=mean_na)
Note: aqp::slice() will be deprecated in aqp version 2.0
--> Please consider using the more efficient aqp::dice()
Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.Warning: Bad horizonation detected, first matching horizon selected. Use strict=TRUE to enforce QA/QC.
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r |> dplyr::select(-c(contributing_fraction)) |> tidyr::pivot_wider(names_from=variable, values_from=value)
dsp_data_points_nlcd.slab.r.1[ is.na(dsp_data_points_nlcd.slab.r.1) ] <- NA
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r.1 |> dplyr::rowwise() |> dplyr::mutate(soc_cl = soc_class(SOC_pct), ph_cl = ph_class(ph_h2o), db_cl = db_class(Bulk_Density), txt_class = gettt(sand_tot_psa, silt_tot_psa, clay_tot_psa))
dsp_data_points_nlcd.slab.r.1 <- dsp_data_points_nlcd.slab.r.1 |> dplyr::ungroup() |> dplyr::rename(pedon_key=pedon_ID)
dsp_data_points_complete <- dsp_data_points_nlcd.slab.r.1 |> dplyr::filter(!is.na(soc_cl) & !is.na(db_cl) & !is.na(ph_cl) & !is.na(txt_class)) |> dplyr::select(pedon_key, top, bottom, soc_cl, ph_cl, db_cl, txt_class) |> dplyr::ungroup() |> dplyr::mutate(pedon_key = as.integer(pedon_key))
dsp_data_points_nlcd <- dplyr::bind_cols(pedon_lab, dsp_nlcd.df)
dsp_data_points_nlcd_data_sub <- dsp_data_points_nlcd |> dplyr::select(pedon_key=pedon_ID, SSL_name=Soil, lat=pedon_y, lon=pedon_x, earthcovkind1=trt,lc) |> dplyr::distinct()
LT_data_points_nlcd_data_sub <- LT_data_points_nlcd_data |> dplyr::select(pedon_key, SSL_name, lat, lon, earthcovkind1,obsdate,lc) |> dplyr::distinct()
dsp_data_points_complete <- dsp_data_points_complete |> dplyr::left_join(dsp_data_points_nlcd_data_sub, by="pedon_key")
combine dataframes
stm_data <- bind_rows(dsp_data_points_complete |> droplevels(), LT_data_points_complete |> dplyr::select(-c(obsdate))|> droplevels())
Error in `bind_rows()`:
! Can't combine `..1$ph_cl` <ordered<10807>> and `..2$ph_cl` <ordered<f70bd>>.
Backtrace:
1. dplyr::bind_rows(...)
5. vctrs (local) `<fn>`()
6. vctrs::vec_default_ptype2(...)
10. vctrs::stop_incompatible_type(...)
11. vctrs:::stop_incompatible(...)
12. vctrs:::stop_vctrs(...)
# Select features
mod <- train(ode_cl_aic_mlr_fs, task = t)
Error in UseMethod("trainLearner") :
no applicable method for 'trainLearner' applied to an object of class "c('bnc', 'RLearnerClassif', 'RLearner', 'Learner')"
Pixel /Index Value Description
1 No Change 2 Change from or to Water 3 Change from or to any of the
four Urban classes (open space; low, medium, and high intensity) 4
Change from Herbaceous Wetland to Woody Wetland, or vice versa 5 Change
from or to Herbaceous Wetland 6 Change from Cultivated Crops to Hay /
Pasture, or vice versa 7 Change from or to Cultivated Crops 8 Change
from or to Hay / Pasture 9 Persistent Grassland and Shrubland change.
This change index attempts to identify changes to persistent Grassland
and Shrubland areas, and to separate them from transitional shrubland
areas such as regenerating forests. 10 Change from or to Barren 11
Change from or to any of the three Forest classes (Evergreen, Deciduous,
and Mixed) 12 Change from or to Woody Wetland
National Land Cover Database Class Legend and Description
Class Value Classification Description
Water
11 Open Water- areas of open water, generally with less than 25%
cover of vegetation or soil.
12 Perennial Ice/Snow- areas characterized by a perennial cover of
ice and/or snow, generally greater than 25% of total cover.
Developed
21 Developed, Open Space- areas with a mixture of some constructed
materials, but mostly vegetation in the form of lawn grasses. Impervious
surfaces account for less than 20% of total cover. These areas most
commonly include large-lot single-family housing units, parks, golf
courses, and vegetation planted in developed settings for recreation,
erosion control, or aesthetic purposes.
22 Developed, Low Intensity- areas with a mixture of constructed
materials and vegetation. Impervious surfaces account for 20% to 49%
percent of total cover. These areas most commonly include single-family
housing units.
23 Developed, Medium Intensity -areas with a mixture of constructed
materials and vegetation. Impervious surfaces account for 50% to 79% of
the total cover. These areas most commonly include single-family housing
units.
24 Developed High Intensity-highly developed areas where people
reside or work in high numbers. Examples include apartment complexes,
row houses and commercial/industrial. Impervious surfaces account for
80% to 100% of the total cover.
Barren
31 Barren Land (Rock/Sand/Clay) - areas of bedrock, desert pavement,
scarps, talus, slides, volcanic material, glacial debris, sand dunes,
strip mines, gravel pits and other accumulations of earthen material.
Generally, vegetation accounts for less than 15% of total cover.
Forest
41 Deciduous Forest- areas dominated by trees generally greater than
5 meters tall, and greater than 20% of total vegetation cover. More than
75% of the tree species shed foliage simultaneously in response to
seasonal change.
42 Evergreen Forest- areas dominated by trees generally greater than
5 meters tall, and greater than 20% of total vegetation cover. More than
75% of the tree species maintain their leaves all year. Canopy is never
without green foliage.
43 Mixed Forest- areas dominated by trees generally greater than 5
meters tall, and greater than 20% of total vegetation cover. Neither
deciduous nor evergreen species are greater than 75% of total tree
cover.
Shrubland
51 Dwarf Scrub- Alaska only areas dominated by shrubs less than 20
centimeters tall with shrub canopy typically greater than 20% of total
vegetation. This type is often co-associated with grasses, sedges,
herbs, and non-vascular vegetation.
52 Shrub/Scrub- areas dominated by shrubs; less than 5 meters tall
with shrub canopy typically greater than 20% of total vegetation. This
class includes true shrubs, young trees in an early successional stage
or trees stunted from environmental conditions.
Herbaceous
71 Grassland/Herbaceous- areas dominated by gramanoid or herbaceous
vegetation, generally greater than 80% of total vegetation. These areas
are not subject to intensive management such as tilling, but can be
utilized for grazing.
72 Sedge/Herbaceous- Alaska only areas dominated by sedges and forbs,
generally greater than 80% of total vegetation. This type can occur with
significant other grasses or other grass like plants, and includes sedge
tundra, and sedge tussock tundra.
73 Lichens- Alaska only areas dominated by fruticose or foliose
lichens generally greater than 80% of total vegetation.
74 Moss- Alaska only areas dominated by mosses, generally greater
than 80% of total vegetation.
Planted/Cultivated
81 Pasture/Hay-areas of grasses, legumes, or grass-legume mixtures
planted for livestock grazing or the production of seed or hay crops,
typically on a perennial cycle. Pasture/hay vegetation accounts for
greater than 20% of total vegetation.
82 Cultivated Crops -areas used for the production of annual crops,
such as corn, soybeans, vegetables, tobacco, and cotton, and also
perennial woody crops such as orchards and vineyards. Crop vegetation
accounts for greater than 20% of total vegetation. This class also
includes all land being actively tilled.
Wetlands
90 Woody Wetlands- areas where forest or shrubland vegetation
accounts for greater than 20% of vegetative cover and the soil or
substrate is periodically saturated with or covered with water.
Denomination ph range
Ultra acid < 3.5 Extremely acid 3.5–4.4 Very strongly acid 4.5–5.0
Strongly acid 5.1–5.5 Moderately acid 5.6–6.0 Slightly acid 6.1–6.5
Neutral 6.6–7.3 Slightly alkaline 7.4–7.8 Moderately alkaline 7.9–8.4
Strongly alkaline 8.5–9.0 Very strongly alkaline > 9.0
SOC classes (4 classes)
Db classes
ph_class <- function(ph){
if(is.na(ph)){
class = NA
}else if(ph <= 3.5){
class = 'Ultra acid'
}else if(ph > 3.5 & ph <= 4.5){
class = 'Extremely acid'
}else if(ph > 4.5 & ph <= 5){
class = 'Very strongly acid'
}else if(ph > 5 & ph < 5.6){
class = 'Strongly acid'
}else if(ph >= 5.6 & ph <= 6){
class = 'Moderately acid'
}else if(ph > 6 & ph <= 6.5){
class = 'Slightly acid'
}else if(ph > 6.5 & ph <= 7.3){
class = 'Neutral'
}else if(ph > 7.3 & ph <= 7.8){
class = 'Slightly alkaline'
}else if(ph > 7.8 & ph <= 8.4){
class = 'Moderately alkaline'
}else if(ph > 8.4 & ph <= 9){
class = 'Strongly alkaline'
}else if(ph > 9 & ph <= 9){
class = 'Very strongly alkaline'
}else {class = NA}
return(class)
}
soc_class <- function(soc){
if(is.na(soc)){
class = NA
}else if(soc <= 1){
class = 'low'
}else if(soc > 1 & soc <= 2){
class = 'moderate'
}else if(soc > 2 & soc <= 3){
class = 'high'
}else if(soc > 3){
class = 'very high'
}else {class = NA}
return(class)
}
db_class <- function(Db){
if(is.na(Db)){
class = NA
}else if(Db <= 1){
class = 'very loose'
}else if(Db > 1 & Db <= 1.2){
class = 'loose'
}else if(Db > 1.2 & Db <= 1.4){
class = 'normal'
}else if(Db > 1.4 & Db <= 1.6){
class = 'hard'
}else if(Db > 1.6){
class = 'compact'
}
return(class)
}
gettt <- function(sand, silt, clay){
if(is.na(sand) | is.na(silt) | is.na(clay)){
x = NA
} else if((silt + 1.5 * clay) < 15){
x = "Sand"
} else if((silt + 1.5 * clay) >= 15 & (silt + 2.0 * clay) < 30){
x = "Loamy sand"
} else if((clay >= 7) & (clay <= 20) & (sand > 52) & ((silt + 2.0 * clay) >= 30)){
x = "Sandy loam"
} else if((clay < 7) & (silt < 50) & ((silt + 2.0 * clay) >= 30)){
x = "Sandy loam"
} else if((clay >= 7) & (clay <= 27) & (silt >= 28) & (silt < 50) & (sand <= 52)){
x = "Loam"
} else if(((silt >= 50) & (clay >= 12) & (clay < 27)) | ((silt >= 50) & (silt < 80) & (clay < 12))){
x = "Silt loam"
} else if((silt >= 80) & (clay < 12)){
x = "Silt"
} else if((clay >= 20) & (clay < 35) & (silt < 28) & (sand > 45)){
x = "Sandy clay loam"
} else if((clay >= 27) & (clay < 40) & (sand > 20) & (sand <= 45)){
x = "Clay loam"
} else if((clay >= 27) & (clay < 40) & (sand <= 20)){
x = "Silty clay loam"
} else if((clay >= 35) & (sand >= 45)){
x = "Sandy clay"
} else if((clay >= 40) & (silt >= 40)){
x = "Silty clay"
} else if((clay >= 40) & (sand <= 45) & (silt < 40)){
x = "Clay"
}
return(x)
}
LS0tCnRpdGxlOiAiUXVhbnQgU1RNIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShoZXJlKQpsaWJyYXJ5KERCSSkKbGlicmFyeShSU1FMaXRlKQpsaWJyYXJ5KHJhc3RlcikKbGlicmFyeShzZikKbGlicmFyeShodHRyKSAjIGdlbmVyaWMgd2Vic2VydmljZSBwYWNrYWdlCmxpYnJhcnkodG1hcCkKYGBgCgpgYGB7cn0KIyBtZWFuIGZ1bmN0aW9uCm1lYW5fbmEgPC0gZnVuY3Rpb24oeCl7CiAgeF9tZWFuIDwtIG1lYW4oeCwgbmEucm09VFJVRSkKICByZXR1cm4oeF9tZWFuKQp9CgojIGNvbm5lY3QKZGIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAnQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL0xQS1NfRGF0YS9EYXRhL1NvaWxfUGVkb25fRGF0YWJhc2VzL05SQ1MvS1NTTC9MYWJEYXRhTWFydF80LTE3LTIzL25jc3NfbGFiZGF0YS5zcWxpdGUnKQoKZGJMaXN0VGFibGVzKGRiKQoKIyBsaXN0IGZpZWxkcwojIGRiTGlzdEZpZWxkcyhkYiwgJ2xhYl9wZWRvbicpCiMgZGJMaXN0RmllbGRzKGRiLCAnbGFiX3NpdGUnKQojIGRiTGlzdEZpZWxkcyhkYiwgJ2xhYl9waHlzaWNhbF9wcm9wZXJ0aWVzJykKIyBkYkxpc3RGaWVsZHMoZGIsICdsYWJfY2hlbWljYWxfcHJvcGVydGllcycpCiMgZGJMaXN0RmllbGRzKGRiLCAnbGFiX2NvbWJpbmVfbmFzaXNfbmNzcycpCmxhYl9sYXllciA8LSBkYkdldFF1ZXJ5KGRiLCAiU0VMRUNUICogZnJvbSBsYWJfbGF5ZXI7IikKbGFiX3NpdGUgPC0gZGJHZXRRdWVyeShkYiwgIlNFTEVDVCAqIGZyb20gbGFiX3NpdGU7IikKbGFiX3BlZG9uIDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9wZWRvbjsiKQpsYWJfcGh5IDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9waHlzaWNhbF9wcm9wZXJ0aWVzOyIpCmxhYl9jaGVtIDwtIGRiR2V0UXVlcnkoZGIsICJTRUxFQ1QgKiBmcm9tIGxhYl9jaGVtaWNhbF9wcm9wZXJ0aWVzOyIpCmxhYl9uYXNpcyA8LSBkYkdldFF1ZXJ5KGRiLCAiU0VMRUNUICogZnJvbSBsYWJfY29tYmluZV9uYXNpc19uY3NzOyIpCgojIHNlcmllcyBpbmNsdWRlZCBpbiB0aGUgTG9hbXkgVGFibGVsYW5kIEVTRApMb2FteV90YWJsZWxhbmQgPC0gYygnVWx5c3NlcycsICdSaWNoZmllbGQnLCAnS2VpdGgnLCAnS3VtYScsICdSb3NlYnVkJywgJ0JsYWNrd29vZCcsICdEYXdlcycsICdNYWNlJywgJ01jQ29uYXVnaHknLCAnTm9ya2EnLCAnU2F0YW50YScsICdXZWxkJykKCkxvYW15X3RhYmxlbGFuZF9uYXNpcyA8LSBsYWJfbmFzaXMgfD4gZHBseXI6OmZpbHRlcihTU0xfbmFtZSAlaW4lIExvYW15X3RhYmxlbGFuZCkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHBlZGxhYnNhbXBudW0sIHBlaWlkLCBzYW1wX25hbWUsY29ycl9uYW1lLCBTU0xfbmFtZSwgbGF0PWxhdGl0dWRlX2RlY2ltYWxfZGVncmVlcywgbG9uPWxvbmdpdHVkZV9kZWNpbWFsX2RlZ3JlZXMpIAoKCnBoeV9sYXllciA8LSBsYWJfcGh5IHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCB0ZXh0dXJlX2xhYiwgY2xheV90b3RhbCwgc2lsdF90b3RhbCwgc2FuZF90b3RhbCwgYnVsa19kZW5zaXR5X3RoaXJkX2JhciwgYWdncmVnYXRlX3N0YWJpbGl0eV8wNV8yX21tLCB3YXRlcl9yZXRlbnRpb25fdGhpcmRfYmFyLCB3YXRlcl9yZXRlbnRpb25fMTVfYmFyLCB3YXRlcl9yZXRlbnRpb25fZmllbGRfc3RhdGUpIHw+IGRwbHlyOjpsZWZ0X2pvaW4obGFiX2xheWVyIHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCBsYWJzYW1wbnVtLCBoem5fdG9wLCBoem5fYm90LCBoem5fZGVzZ24sIGh6bl9tYXN0ZXIsIHBlZG9uX2tleSwgc2l0ZV9rZXkpLCBieT0ibGF5ZXJfa2V5IikKCnBoeV9jaGVtX2xheWVyIDwtIHBoeV9sYXllciB8PiBkcGx5cjo6bGVmdF9qb2luKGxhYl9jaGVtIHw+IGRwbHlyOjpzZWxlY3QobGF5ZXJfa2V5LCBwaF9oMm8sdG90YWxfY2FyYm9uX25jcywgdG90YWxfbml0cm9nZW5fbmNzLCBvcmdhbmljX2NhcmJvbl93YWxrbGV5X2JsYWNrLGVzdGltYXRlZF9vcmdhbmljX2NhcmJvbiwgY2FyYm9uX3RvX25pdHJvZ2VuX3JhdGlvKSwgYnk9ImxheWVyX2tleSIpCgoKTFRfcGh5X2NoZW0gPC0gTG9hbXlfdGFibGVsYW5kX25hc2lzIHw+IGRwbHlyOjpsZWZ0X2pvaW4ocGh5X2NoZW1fbGF5ZXIgLCBieT1jKCJwZWRvbl9rZXkiKSkgfD4gZHBseXI6OmZpbHRlcighaXMubmEobGF0KSkKCmBgYAoKYGBge3J9CiNOQVNJUyB0YWJsZXMKIyBwZWRvbiAgdG8gc2l0ZW9iczogc2l0ZW9ic2lpZHJlZj09c2l0ZW9ic2lpZAoKcGVkb24gPC0gZGF0YS50YWJsZTo6ZnJlYWQoIkM6L1JfRHJpdmUvRGF0YV9GaWxlcy9MUEtTX0RhdGEvRGF0YS9Tb2lsX1BlZG9uX0RhdGFiYXNlcy9OUkNTL05BU0lTL05BU0lTX0FQUklMXzIwMTcvQ1NWX2ZpbGVzL3BlZG9uLmNzdiIsCiAgICBzZXAgPSAifCIsIGhlYWRlciA9IFQpCgpzaXRlb2JzIDwtIGRhdGEudGFibGU6OmZyZWFkKCJDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTFBLU19EYXRhL0RhdGEvU29pbF9QZWRvbl9EYXRhYmFzZXMvTlJDUy9OQVNJUy9OQVNJU19BUFJJTF8yMDE3L0NTVl9maWxlcy9zaXRlb2JzLmNzdiIsCiAgICBzZXAgPSAifCIsIGhlYWRlciA9IFQpCgoKbmFzaXNfcGVkb24gPC0gcGVkb24gfD4gZHBseXI6OnNlbGVjdChwZWlpZCwgc2l0ZW9ic2lpZHJlZiwgZWFydGhjb3ZraW5kMSwgZWFydGhjb3ZraW5kMiwgcGVkbGFic2FtcG51bSkgfD4gZHBseXI6OmxlZnRfam9pbihzaXRlb2JzIHw+IGRwbHlyOjpzZWxlY3Qoc2l0ZW9ic2lpZCwgb2JzZGF0ZSksIGJ5PWMoJ3NpdGVvYnNpaWRyZWYnPSdzaXRlb2JzaWlkJykpCgoKI2pvaW4gdG8gTFRfcGh5X2NoZW0KCkxUX3BoeV9jaGVtX25hc2lzIDwtIExUX3BoeV9jaGVtIHw+IGRwbHlyOjpsZWZ0X2pvaW4obmFzaXNfcGVkb24sIGJ5PSJwZWlpZCIpIHw+IGRwbHlyOjpkaXN0aW5jdCgpCmBgYAoKCmBgYHtyfQpMVF9kYXRhX3BvaW50cyA8LSBzdF9hc19zZihMVF9waHlfY2hlbSwgY29vcmRzID0gYygibG9uIiwibGF0IiksIGNycyA9IDQzMjYpCgojIFN0YXRlL01MUkEgQm91bmRhcnkKCiN3ZnNfbWxyYSA8LSAnaHR0cHM6Ly9zZXJ2aWNlcy5hcmNnaXMuY29tL1NYYkRwbWI3eFFrazQ0SlYvQXJjR0lTL3Jlc3Qvc2VydmljZXMvVVNfTUxSQS9GZWF0dXJlU2VydmVyJwp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vU1hiRHBtYjd4UWtrNDRKVi9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpCnVybCRwYXRoIDwtIHBhc3RlKHVybCRwYXRoLCAiVVNfTUxSQS9GZWF0dXJlU2VydmVyLzAvcXVlcnkiLCBzZXAgPSAiLyIpCnVybCRxdWVyeSA8LSBsaXN0KHdoZXJlID0gIjE9MSIsCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwKICAgICAgICAgICAgICAgICAgcmV0dXJuR2VvbWV0cnkgPSAidHJ1ZSIsCiAgICAgICAgICAgICAgICAgIGYgPSAiZ2VvanNvbiIpCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkKbWxyYSA8LSBzdF9yZWFkKHJlcXVlc3QpCgojd2ZzX3N0YXRlcyA8LSAnaHR0cHM6Ly9zZXJ2aWNlcy5hcmNnaXMuY29tL1NYYkRwbWI3eFFrazQ0SlYvQXJjR0lTL3Jlc3Qvc2VydmljZXMvVVNBX1N0YXRlc19HZW5lcmFsaXplZC9GZWF0dXJlU2VydmVyJwp1cmwgPC0gcGFyc2VfdXJsKCJodHRwczovL3NlcnZpY2VzLmFyY2dpcy5jb20vU1hiRHBtYjd4UWtrNDRKVi9hcmNnaXMvcmVzdC9zZXJ2aWNlcyIpCnVybCRwYXRoIDwtIHBhc3RlKHVybCRwYXRoLCAiVVNBX1N0YXRlc19HZW5lcmFsaXplZC9GZWF0dXJlU2VydmVyLzAvcXVlcnkiLCBzZXAgPSAiLyIpCnVybCRxdWVyeSA8LSBsaXN0KHdoZXJlID0gIjE9MSIsCiAgICAgICAgICAgICAgICAgIG91dEZpZWxkcyA9ICIqIiwKICAgICAgICAgICAgICAgICAgcmV0dXJuR2VvbWV0cnkgPSAidHJ1ZSIsCiAgICAgICAgICAgICAgICAgIGYgPSAiZ2VvanNvbiIpCnJlcXVlc3QgPC0gYnVpbGRfdXJsKHVybCkKc3RhdGVzIDwtIHN0X3JlYWQocmVxdWVzdCkKc3RhdGVzIDwtIHN0X2Nyb3Aoc3RhdGVzLCBtbHJhKQoKCnRtYXBfbW9kZSgidmlldyIpCiAgdG1fc2hhcGUoc3RhdGVzKSArCiAgICB0bV9ib3JkZXJzKCkgKwogICAgdG1fbGluZXMobHdkID0gInN0cm9rZWx3ZCIsIGxlZ2VuZC5sd2Quc2hvdyA9IEZBTFNFKSArCiAgICB0bV9zaGFwZShMVF9kYXRhX3BvaW50cykgKwogICAgdG1fZG90cyhjb2w9IiMxQjlFNzciLCBzaXplPTAuMykgKwogICAgCiAgICAjdG1fc2NhbGVfYmFyKHBvc2l0aW9uID0gYygwLjA2LCAwLjA1KSkgKwogICAgdG1fYWRkX2xlZ2VuZCgnZmlsbCcsIAoJY29sID0gYyggIiMxQjlFNzciKSwKCWJvcmRlci5jb2wgPSAiZ3JleTQwIiwKCXNpemUgPSAxLAoJbGFiZWxzID0gYygnS1NTTCcpLAoJdGl0bGU9IlBvdGVudGlhbCBTYW1wbGluZyBBcmVhcyIpICsKICAgIHRtX2xheW91dChtYWluLnRpdGxlID0gIkxvYW15IFRhYmxlbGFuZCBFU0QiLCBiZy5jb2xvciA9ICJ3aGl0ZSIsIGxlZ2VuZC5vdXRzaWRlID0gVFJVRSkgKwogICAgdG1fdmlldyhzZXQudmlldyA9IGMoLTk5LjIyLCAzOS4xMywgIDQpKQoKYGBgCgpgYGB7cn0KbGlicmFyeShyYXN0ZXIpCgoKbmxjZF9jaGFuZ2UgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwMV8yMDE5X2NoYW5nZV9pbmRleF9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCkx0X25sY2RfY2hhbmdlIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkX2NoYW5nZSwgTFRfZGF0YV9wb2ludHMpCgpubGNkMDEgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwMV9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDA0IDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMDRfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCm5sY2QwNiA8LSByYXN0ZXI6OnJhc3RlcignQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL05SQ1MvTkxDRF9FU0QvTkxDRF8yMDA2X0xhbmRfQ292ZXJfTDQ4XzIwMjEwNjA0XzlaZGlicGhoc3JQVHhkZ1pLT2pwLnRpZmYnKQpubGNkMDggPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAwOF9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDExIDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMTFfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCm5sY2QxMyA8LSByYXN0ZXI6OnJhc3RlcignQzovUl9Ecml2ZS9EYXRhX0ZpbGVzL05SQ1MvTkxDRF9FU0QvTkxDRF8yMDEzX0xhbmRfQ292ZXJfTDQ4XzIwMjEwNjA0XzlaZGlicGhoc3JQVHhkZ1pLT2pwLnRpZmYnKQpubGNkMTYgPC0gcmFzdGVyOjpyYXN0ZXIoJ0M6L1JfRHJpdmUvRGF0YV9GaWxlcy9OUkNTL05MQ0RfRVNEL05MQ0RfMjAxNl9MYW5kX0NvdmVyX0w0OF8yMDIxMDYwNF85WmRpYnBoaHNyUFR4ZGdaS09qcC50aWZmJykKbmxjZDE5IDwtIHJhc3Rlcjo6cmFzdGVyKCdDOi9SX0RyaXZlL0RhdGFfRmlsZXMvTlJDUy9OTENEX0VTRC9OTENEXzIwMTlfTGFuZF9Db3Zlcl9MNDhfMjAyMTA2MDRfOVpkaWJwaGhzclBUeGRnWktPanAudGlmZicpCkx0X25sY2RfMDEgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwMSwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDQgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwNCwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDYgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwNiwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMDggPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QwOCwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTEgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxMSwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTMgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxMywgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTYgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxNiwgTFRfZGF0YV9wb2ludHMpCkx0X25sY2RfMTkgPC0gcmFzdGVyOjpleHRyYWN0KG5sY2QxOSwgTFRfZGF0YV9wb2ludHMpCgpMdF9ubGNkLmRmIDwtIGRhdGEuZnJhbWUoTHRfbmxjZF9jaGFuZ2UsIEx0X25sY2RfMDEsIEx0X25sY2RfMDQsIEx0X25sY2RfMDYsIEx0X25sY2RfMDgsIEx0X25sY2RfMTEsIEx0X25sY2RfMTMsIEx0X25sY2RfMTYsIEx0X25sY2RfMTkpIHw+IHB1cnJyOjpzZXRfbmFtZXMoJ25sY2RfY2hhbmdlJywgJ25sY2QwMScsICdubGNkMDQnLCAnbmxjZDA2JywgJ25sY2QwOCcsICdubGNkMTEnLCAnbmxjZDEzJywgJ25sY2QxNicsICdubGNkMTknLCApCkx0X25sY2QuZGYgPC0gTHRfbmxjZC5kZiB8PiBkcGx5cjo6bXV0YXRlKGxjID0gZHBseXI6OmNhc2Vfd2hlbihubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODIgfiAnQ3JvcHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODEgfiAnUGFzdHVyZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5sY2RfY2hhbmdlPT0xICYgbmxjZDE5PT03MSB+ICdHcmFzc2xhbmQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NTIgfiAnU2hydWItQ3JvcDA3JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxjZF9jaGFuZ2U9PTcgJiBubGNkMDg9PTcxIH4gJ0dyYXNzbGFuZC1Dcm9wMDknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NzEgJiBubGNkMDg9PTgyIH4gJ0dyYXNzbGFuZC1Dcm9wMDcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJ0ZhaWwnKSkKCkxUX2RhdGFfcG9pbnRzX25sY2RfZGF0YSA8LSBkcGx5cjo6YmluZF9jb2xzKExUX3BoeV9jaGVtX25hc2lzLCBMdF9ubGNkLmRmKQoKTFRfZGF0YV9wb2ludHNfbmxjZCA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OmZpbHRlcighaXMubmEodGV4dHVyZV9sYWIpLCAhaHpuX2JvdCA8IGh6bl90b3AsICFoem5fYm90ID09IGh6bl90b3ApCgphcXA6OmRlcHRocyhMVF9kYXRhX3BvaW50c19ubGNkKSA8LSAgcGVkb25fa2V5IH4gaHpuX3RvcCAgKyBoem5fYm90IApMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciA8LSBhcXA6OnNsYWIoTFRfZGF0YV9wb2ludHNfbmxjZCwgZm0gPSBwZWRvbl9rZXkgfiBjbGF5X3RvdGFsICsgc2lsdF90b3RhbCArIHNhbmRfdG90YWwgKyBidWxrX2RlbnNpdHlfdGhpcmRfYmFyICsgcGhfaDJvICsgb3JnYW5pY19jYXJib25fd2Fsa2xleV9ibGFjayArIGVzdGltYXRlZF9vcmdhbmljX2NhcmJvbiArIGFnZ3JlZ2F0ZV9zdGFiaWxpdHlfMDVfMl9tbSwgc2xhYi5zdHJ1Y3R1cmU9YygwLDE1KSwgc2xhYi5mdW49bWVhbl9uYSkKTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSA8LSBMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciB8PiBkcGx5cjo6c2VsZWN0KC1jKGNvbnRyaWJ1dGluZ19mcmFjdGlvbikpIHw+IHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tPXZhcmlhYmxlLCB2YWx1ZXNfZnJvbT12YWx1ZSkKTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMVsgaXMubmEoTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSkgXSA8LSBOQQpMVF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIExUX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgfD4gZHBseXI6OnJvd3dpc2UoKSB8PiBkcGx5cjo6bXV0YXRlKHNvYyA9IGlmX2Vsc2UoIWlzLm5hKG9yZ2FuaWNfY2FyYm9uX3dhbGtsZXlfYmxhY2spLCBvcmdhbmljX2NhcmJvbl93YWxrbGV5X2JsYWNrLCBlc3RpbWF0ZWRfb3JnYW5pY19jYXJib24pKXw+IGRwbHlyOjptdXRhdGUoc29jX2NsID0gc29jX2NsYXNzKHNvYyksIHBoX2NsID0gcGhfY2xhc3MocGhfaDJvKSwgZGJfY2wgPSBkYl9jbGFzcyhidWxrX2RlbnNpdHlfdGhpcmRfYmFyKSwgdHh0X2NsYXNzID0gZ2V0dHQoc2FuZF90b3RhbCwgc2lsdF90b3RhbCwgY2xheV90b3RhbCkpCgoKTFRfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gTFRfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSB8PiBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzb2NfY2wpICYgIWlzLm5hKGRiX2NsKSAmICFpcy5uYShwaF9jbCkgJiAhaXMubmEodHh0X2NsYXNzKSkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHRvcCwgYm90dG9tLCBzb2NfY2wsIHBoX2NsLCBkYl9jbCwgdHh0X2NsYXNzKSB8PiBkcGx5cjo6dW5ncm91cCgpIHw+IGRwbHlyOjptdXRhdGUocGVkb25fa2V5ID0gYXMuaW50ZWdlcihwZWRvbl9rZXkpKQoKTFRfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIFNTTF9uYW1lLCBsYXQsIGxvbiwgZWFydGhjb3ZraW5kMSxvYnNkYXRlLGxjKSB8PiBkcGx5cjo6ZGlzdGluY3QoKQoKTFRfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gTFRfZGF0YV9wb2ludHNfY29tcGxldGUgfD4gZHBseXI6OmxlZnRfam9pbihMVF9kYXRhX3BvaW50c19ubGNkX2RhdGFfc3ViLCBieT0icGVkb25fa2V5IikKYGBgCgojRFNQNFNIIGRhdGFiYXNlCmBgYHtyfQpsaWJyYXJ5KERCSSkKbGlicmFyeShSU1FMaXRlKQpsaWJyYXJ5KGRwbHlyLCB3YXJuLmNvbmZsaWN0cyA9IEZBTFNFKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShyZWFkcikKbGlicmFyeShoZXJlKQoKZHNwNHNoNCA8LSBkYkNvbm5lY3QoU1FMaXRlKCksIGhlcmUoImRhdGEvcmF3X2RhdGEvZHNwNHNoNC5kYiIpKQpkYkxpc3RUYWJsZXMoZHNwNHNoNCkgI1RvIGNoZWNrIHRhYmxlcwoKcGVkb24gPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBwZWRvbjsiKQpjb29wX2xhYiA8LSBkYkdldFF1ZXJ5KGRzcDRzaDQsICJTRUxFQ1QgKiBmcm9tIGNvb3BsYWJtc3Q7IikKa3NzbF9sYWIgPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBrc3NsbGFibXN0OyIpCmxheWVyZGVzYyA8LSBkYkdldFF1ZXJ5KGRzcDRzaDQsICJTRUxFQ1QgKiBmcm9tIGxheWVyZGVzY3JpcHRpb247IikKbGF5ZXJkZXNnIDwtIGRiR2V0UXVlcnkoZHNwNHNoNCwgIlNFTEVDVCAqIGZyb20gbGF5ZXJkZXNpZ25hdGlvbjsiKQpwbG90IDwtIGRiR2V0UXVlcnkoZHNwNHNoNCwgIlNFTEVDVCAqIGZyb20gcGxvdG92ZXJ2aWV3OyIpCmRzcHBsb3RtZ3QgPC0gZGJHZXRRdWVyeShkc3A0c2g0LCAiU0VMRUNUICogZnJvbSBkc3BwbG90bWd0OyIpCgpsYWIgPC0gY29vcF9sYWIgfD4gZHBseXI6OnNlbGVjdCgtYyhEU1BfUGVkb24pKSB8PiBkcGx5cjo6bGVmdF9qb2luKGtzc2xfbGFiLCBieT1jKCdLU1NMX2xhYnNhbXBudW0nPSduYXR1cmFsX2tleScpKQpwZWRvbl9sYWIgPC0gcGVkb24gfD4gZHBseXI6OmxlZnRfam9pbihsYWIsIGJ5PSdEU1BfUGVkb25fSUQnKQpwZWRvbl9sYWIgPC0gcGVkb25fbGFiIHw+IGRwbHlyOjpsZWZ0X2pvaW4oZHNwcGxvdG1ndCB8PiBkcGx5cjo6c2VsZWN0KC1jKFNvaWwpKSwgYnk9J0RTUF9QbG90X0lEJykKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6bGVmdF9qb2luKGxheWVyZGVzYyB8PiBkcGx5cjo6cmVuYW1lKGZpZWxkX2NsYXlfcGN0ID0gQ2xheV9wY3QpLCBieT1jKCdEU1BfUGVkb25fSUQnPSdEU1BfUGVkb25fSUQnLCAnRFNQX3NhbXBsZV9JRCc9J0RTUF9zYW1wbGVfSUQnKSkKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6bGVmdF9qb2luKGxheWVyZGVzZywgYnk9YygnRFNQX1BlZG9uX0lEJz0nRFNQX1BlZG9uX0lEJywgJ0RTUF9zYW1wbGVfSUQnPSdEU1Bfc2FtcGxlX0lEJykpCnBlZG9uX2xhYiA8LSBwZWRvbl9sYWIgfD4gZHBseXI6OmZpbHRlcihTb2lsPT0iS2VpdGgiKQoKcGVkb25fbGFiIDwtIHBlZG9uX2xhYiB8PiBkcGx5cjo6c2VsZWN0KGMocGVkb25fSUQsRFNQX1BlZG9uX0lELERTUF9QbG90X0lELERTUF9zYW1wbGVfSUQsTFUsdGlsbCx0cnQsIHBlZG9uX3gscGVkb25feSxTb2lsLEJ1bGtfRGVuc2l0eSxXYXRlcl9Db250ZW50LFNPQ19wY3QsS1NTTF9XU0EsWW9kZXJfQWdnU3RhYl9NV0QsU29pbF9SZXNwaXJhdGlvbixCZ2x1Y29zaWRhc2UsQmdsdWNvc2FtaW5pZGFzZSxBbGthbGluZVBob3NwaGF0YXNlLEFjaWRQaG9zcGhhdGFzZSxQaG9zcGhvZGllc3RlcmFzZSxQT1hfQyxBQ0UsS1NTTF9sYWJzYW1wbnVtLGhvcml6b25fZGVzaWduYXRpb24sbGF5X2RlcHRoX3RvX3RvcCwgbGF5X2RlcHRoX3RvX2JvdHRvbSxjbGF5X3RvdF9wc2Esc2lsdF90b3RfcHNhLHNhbmRfdG90X3BzYSxjbzNfY2x5LHRleF9wc2RhLGFkb2QsY2FjbzMscGhfY2FjbDIscGhfaDJvLENLTW5PNCxQTml0cm9CR2x1LGFnX3N0YWIsY190b3RfbmNzLG5fdG90X25jcyxzX3RvdF9uY3MsZXN0aW1hdGVkX29yZ2FuaWNfQyxGaWVsZF9UZXh0dXJlLENvYXJzZV9GcmFnX3ZvbHVtZSxmaWVsZF9jbGF5X3BjdCxDb2xvcl9Nb2lzdF9IdWUsQ29sb3JfTW9pc3RfVmFsdWUsQ29sb3JfTW9pc3RfQ2hyb21hKSkKCgpwZWRvbl9sYWJfcG9pbnRzIDwtIHN0X2FzX3NmKHBlZG9uX2xhYiwgY29vcmRzID0gYygicGVkb25feCIsInBlZG9uX3kiKSwgY3JzID0gNDMyNikKCmRzcF9ubGNkX2NoYW5nZSA8LSByYXN0ZXI6OmV4dHJhY3QobmxjZF9jaGFuZ2UsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzAxIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDEsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA0IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDQsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA2IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDYsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzA4IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMDgsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzExIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTEsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzEzIDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTMsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzE2IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTYsIHBlZG9uX2xhYl9wb2ludHMpCmRzcF9ubGNkXzE5IDwtIHJhc3Rlcjo6ZXh0cmFjdChubGNkMTksIHBlZG9uX2xhYl9wb2ludHMpCgpkc3BfbmxjZC5kZiA8LSBkYXRhLmZyYW1lKGRzcF9ubGNkX2NoYW5nZSwgZHNwX25sY2RfMDEsIGRzcF9ubGNkXzA0LCBkc3BfbmxjZF8wNiwgZHNwX25sY2RfMDgsIGRzcF9ubGNkXzExLCBkc3BfbmxjZF8xMywgZHNwX25sY2RfMTYsIGRzcF9ubGNkXzE5KSB8PiBwdXJycjo6c2V0X25hbWVzKCdubGNkX2NoYW5nZScsICdubGNkMDEnLCAnbmxjZDA0JywgJ25sY2QwNicsICdubGNkMDgnLCAnbmxjZDExJywgJ25sY2QxMycsICdubGNkMTYnLCAnbmxjZDE5JywgKQpkc3BfbmxjZC5kZiA8LSBkc3BfbmxjZC5kZiB8PiBkcGx5cjo6bXV0YXRlKGxjID0gZHBseXI6OmNhc2Vfd2hlbihubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODIgfiAnQ3JvcHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09MSAmIG5sY2QxOT09ODEgfiAnUGFzdHVyZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5sY2RfY2hhbmdlPT0xICYgbmxjZDE5PT03MSB+ICdHcmFzc2xhbmQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NTIgfiAnU2hydWItQ3JvcDA3JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxjZF9jaGFuZ2U9PTcgJiBubGNkMDg9PTcxIH4gJ0dyYXNzbGFuZC1Dcm9wMDknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGNkX2NoYW5nZT09NyAmIG5sY2QwNj09NzEgJiBubGNkMDg9PTgyIH4gJ0dyYXNzbGFuZC1Dcm9wMDcnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJ0ZhaWwnKSkKCmRzcF9kYXRhX3BvaW50c19ubGNkX2RhdGEgPC0gZHBseXI6OmJpbmRfY29scyhwZWRvbl9sYWIsIGRzcF9ubGNkLmRmKQoKYXFwOjpkZXB0aHMoZHNwX2RhdGFfcG9pbnRzX25sY2RfZGF0YSkgPC0gIHBlZG9uX0lEIH4gbGF5X2RlcHRoX3RvX3RvcCAgKyBsYXlfZGVwdGhfdG9fYm90dG9tIApkc3BfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIgPC0gYXFwOjpzbGFiKGRzcF9kYXRhX3BvaW50c19ubGNkX2RhdGEsIGZtID0gcGVkb25fSUQgfiBjbGF5X3RvdF9wc2EgKyBzaWx0X3RvdF9wc2EgKyBzYW5kX3RvdF9wc2EgKyBCdWxrX0RlbnNpdHkgKyBwaF9oMm8gKyBTT0NfcGN0ICsgS1NTTF9XU0EsIHNsYWIuc3RydWN0dXJlPWMoMCwxNSksIHNsYWIuZnVuPW1lYW5fbmEpCmRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuciB8PiBkcGx5cjo6c2VsZWN0KC1jKGNvbnRyaWJ1dGluZ19mcmFjdGlvbikpIHw+IHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tPXZhcmlhYmxlLCB2YWx1ZXNfZnJvbT12YWx1ZSkKZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjFbIGlzLm5hKGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xKSBdIDwtIE5BCmRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIDwtIGRzcF9kYXRhX3BvaW50c19ubGNkLnNsYWIuci4xIHw+IGRwbHlyOjpyb3d3aXNlKCkgfD4gZHBseXI6Om11dGF0ZShzb2NfY2wgPSBzb2NfY2xhc3MoU09DX3BjdCksIHBoX2NsID0gcGhfY2xhc3MocGhfaDJvKSwgZGJfY2wgPSBkYl9jbGFzcyhCdWxrX0RlbnNpdHkpLCB0eHRfY2xhc3MgPSBnZXR0dChzYW5kX3RvdF9wc2EsIHNpbHRfdG90X3BzYSwgY2xheV90b3RfcHNhKSkKZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgPC0gZHNwX2RhdGFfcG9pbnRzX25sY2Quc2xhYi5yLjEgfD4gZHBseXI6OnVuZ3JvdXAoKSB8PiBkcGx5cjo6cmVuYW1lKHBlZG9uX2tleT1wZWRvbl9JRCkKCmRzcF9kYXRhX3BvaW50c19jb21wbGV0ZSA8LSBkc3BfZGF0YV9wb2ludHNfbmxjZC5zbGFiLnIuMSB8PiBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzb2NfY2wpICYgIWlzLm5hKGRiX2NsKSAmICFpcy5uYShwaF9jbCkgJiAhaXMubmEodHh0X2NsYXNzKSkgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIHRvcCwgYm90dG9tLCBzb2NfY2wsIHBoX2NsLCBkYl9jbCwgdHh0X2NsYXNzKSB8PiBkcGx5cjo6dW5ncm91cCgpIHw+IGRwbHlyOjptdXRhdGUocGVkb25fa2V5ID0gYXMuaW50ZWdlcihwZWRvbl9rZXkpKQoKZHNwX2RhdGFfcG9pbnRzX25sY2QgPC0gZHBseXI6OmJpbmRfY29scyhwZWRvbl9sYWIsIGRzcF9ubGNkLmRmKQpkc3BfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBkc3BfZGF0YV9wb2ludHNfbmxjZCB8PiBkcGx5cjo6c2VsZWN0KHBlZG9uX2tleT1wZWRvbl9JRCwgU1NMX25hbWU9U29pbCwgbGF0PXBlZG9uX3ksIGxvbj1wZWRvbl94LCBlYXJ0aGNvdmtpbmQxPXRydCxsYykgfD4gZHBseXI6OmRpc3RpbmN0KCkKTFRfZGF0YV9wb2ludHNfbmxjZF9kYXRhX3N1YiA8LSBMVF9kYXRhX3BvaW50c19ubGNkX2RhdGEgfD4gZHBseXI6OnNlbGVjdChwZWRvbl9rZXksIFNTTF9uYW1lLCBsYXQsIGxvbiwgZWFydGhjb3ZraW5kMSxvYnNkYXRlLGxjKSB8PiBkcGx5cjo6ZGlzdGluY3QoKQpkc3BfZGF0YV9wb2ludHNfY29tcGxldGUgPC0gZHNwX2RhdGFfcG9pbnRzX2NvbXBsZXRlIHw+IGRwbHlyOjpsZWZ0X2pvaW4oZHNwX2RhdGFfcG9pbnRzX25sY2RfZGF0YV9zdWIsIGJ5PSJwZWRvbl9rZXkiKQoKYGBgCgojIGNvbWJpbmUgZGF0YWZyYW1lcwpgYGB7cn0Kc3RtX2RhdGEgPC0gYmluZF9yb3dzKGRzcF9kYXRhX3BvaW50c19jb21wbGV0ZSwgTFRfZGF0YV9wb2ludHNfY29tcGxldGUgfD4gZHBseXI6OnNlbGVjdCgtYyhvYnNkYXRlKSkpCgpzdG1fZGF0YSA8LSBzdG1fZGF0YSB8PiBkcGx5cjo6bXV0YXRlKHNvY19jbCA9IGZhY3Rvcihzb2NfY2wsIG9yZGVyPVRSVUUsIGxldmVscz1jKCdsb3cnLCAnbW9kZXJhdGUnLCAnaGlnaCcsICd2ZXJ5IGhpZ2gnKSksIGRiX2NsID0gZmFjdG9yKGRiX2NsLCBvcmRlcj1UUlVFLCBsZXZlbHM9YygndmVyeSBsb29zZScsICdsb29zZScsICdub3JtYWwnLCAnaGFyZCcsICdjb21wYWN0JykpLCBwaF9jbCA9IGZhY3RvcihwaF9jbCwgb3JkZXI9VFJVRSwgbGV2ZWxzPWMoIlN0cm9uZ2x5IGFjaWQiLCAiTW9kZXJhdGVseSBhY2lkIiwgIlNsaWdodGx5IGFjaWQiLCAiTmV1dHJhbCIsICJTbGlnaHRseSBhbGthbGluZSIsICJNb2RlcmF0ZWx5IGFsa2FsaW5lIikpLCB0eHRfY2xhc3MgPSBmYWN0b3IodHh0X2NsYXNzLCBvcmRlcj1UUlVFLCBsZXZlbHM9dGV4dHVyZXMpKSAKCnN0bV9kYXRhIDwtIHN0bV9kYXRhIHw+IGRwbHlyOjptdXRhdGUobGM9IGlmX2Vsc2UobGM9PSJGYWlsIiwgIkdyYXNzbGFuZCIsIGxjKSkKCgpgYGAKCmBgYHtyfQoKbGlicmFyeShibmNsYXNzaWZ5KQpzdG1fZGF0YV9zdWIgPC0gc3RtX2RhdGEgfD4gZHBseXI6OmZpbHRlcihsYz09IkNyb3BzIiB8IGxjPT0iR3Jhc3NsYW5kIikgfD4gZHBseXI6OnNlbGVjdChsYywgdHh0X2NsYXNzLCBkYl9jbCwgcGhfY2wsIHNvY19jbCkgfD4gZHBseXI6Om11dGF0ZShsYz1mYWN0b3IobGMpKSB8PiBhcy5kYXRhLmZyYW1lKCkKc3RtX2RhdGFfc3ViIDwtIHN0bV9kYXRhIHw+IGRwbHlyOjpzZWxlY3QobGMsIHR4dF9jbGFzcywgZGJfY2wsIHBoX2NsLCBzb2NfY2wpIHw+IGRwbHlyOjptdXRhdGUobGM9ZmFjdG9yKGxjKSkKCnN0bV9kYXRhX3N1YiA8LSBzdG1fZGF0YV9zdWIgfD4gZHBseXI6Om11dGF0ZSh0eHRfY2xhc3MgPSBmYWN0b3IodHh0X2NsYXNzLCBvcmRlcj1GKSwgcGhfY2wgPSBmYWN0b3IocGhfY2wsIG9yZGVyPUYpLCBzb2NfY2wgPSBmYWN0b3Ioc29jX2NsLCBvcmRlcj1GKSwgZGJfY2wgPSBmYWN0b3IoZGJfY2wsIG9yZGVyPUYpKSB8PiBhcy5kYXRhLmZyYW1lKCkKCm5iIDwtIG5iKCdsYycsIHN0bV9kYXRhX3N1YikgIyBMZWFybiBhIG5haXZlIEJheWVzIHN0cnVjdHVyZQpuYiA8LSBscChuYiwgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAxKSAjIExlYXJuIHBhcmFtZXRlcnMKCmN2KG5iLCBzdG1fZGF0YV9zdWIsIGsgPSAxMCkgIyAxMC1mb2xkIENyb3NzLXZhbGlkYXRpb24gZXN0aW1hdGUgb2YgYWNjdXJhY3kKIz4gWzFdIDAuODU3NjA0NQpoZWFkKHByZWRpY3QobmIsIHN0bV9kYXRhX3N1YikpICMgQ2xhc3NpZnkgdGhlIGVudGlyZSBkYXRhIHNldAojPiBbMV0gdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MgdW5hY2MKIz4gTGV2ZWxzOiB1bmFjYyBhY2MgZ29vZCB2Z29vZAojPiAKIz4gIyBOYWl2ZSBCYXllcwpuYiA8LSBuYignbGMnLCBzdG1fZGF0YV9zdWIpCiMgT0RFIENob3ctTGl1IHdpdGggQUlDIHNjb3JlIChwZW5hbGl6ZWQgbG9nLWxpa2VsaWhvb2QpCm9kZV9jbF9haWMgPC0gdGFuX2NsKCdsYycsIHN0bV9kYXRhX3N1Yiwgc2NvcmUgPSAnYWljJykKIyBTZW1pLW5haXZlIEJheWVzIHdpdGggZm9yd2FyZCBzZXF1ZW50aWFsIHNlbGVjdGlvbiBhbmQgam9pbmluZyAoRlNTSikgYW5kCiMgNS1mb2xkIGNyb3NzLXZhbGlkYXRpb24KZnNzaiA8LSBmc3NqKCdsYycsIHN0bV9kYXRhX3N1YiwgayA9IDUsIGVwc2lsb24gPSAwKQoKcGxvdChvZGVfY2xfYWljKQoKCm5iIDwtIGxwKG5iLCBzdG1fZGF0YV9zdWIsIHNtb290aCA9IDAuMDEpCmF3bmIgPC0gbHAobmIsIHN0bV9kYXRhX3N1Yiwgc21vb3RoID0gMC4wMSwgYXduYl90cmVlcyA9IDEwLCBhd25iX2Jvb3RzdHJhcCA9IDAuNSkKbWFuYiA8LSBscChuYiwgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAwLjAxLCBtYW5iX3ByaW9yID0gMC41KQpvZGVfY2xfYWljIDwtIGJuYygndGFuX2NsJywgJ2xjJywgc3RtX2RhdGFfc3ViLCBzbW9vdGggPSAxLCBkYWdfYXJncyA9IGxpc3Qoc2NvcmUgPSAnYWljJykpCmxvZ0xpayhvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIpCkFJQyhvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIpCnAgPC0gcHJlZGljdChuYiwgc3RtX2RhdGFfc3ViKQphY2N1cmFjeShwLCBzdG1fZGF0YV9zdWIkbGMpCgpzZXQuc2VlZCgwKQpjdihvZGVfY2xfYWljLCBzdG1fZGF0YV9zdWIsIGsgPSAxMCkKY3Yob2RlX2NsX2FpYywgc3RtX2RhdGFfc3ViLCBrID0gMjAsIGRhZyA9IEZBTFNFLCBtZWFuID0gRkFMU0UpCmNtaSgndHh0X2NsYXNzJywgJ3NvY19jbCcsIHN0bV9kYXRhX3N1YiwgJ2xjJykKCgoKbGlicmFyeShtbHIpCm9kZV9jbF9haWNfbWxyIDwtIGFzX21scihvZGVfY2xfYWljLCBkYWcgPSBUUlVFLCBpZCA9ICJvZGVfY2xfYWljIikKCiMgNS1mb2xkIGNyb3NzLXZhbGlkYXRpb24KcmRlc2MgPSBtYWtlUmVzYW1wbGVEZXNjKCJDViIsIGl0ZXJzID0gMikKIyBzZXF1ZW50aWFsIGZsb2F0aW5nIGZvcndhcmQgc2VhcmNoCmN0cmwgPSBtYWtlRmVhdFNlbENvbnRyb2xTZXF1ZW50aWFsKG1ldGhvZCA9ICJzZnMiLCBhbHBoYSA9IDApCiMgV3JhcCBvZGVfY2xfYWljX21sciB3aXRoIGZlYXR1cmUgc2VsZWN0aW9uCm9kZV9jbF9haWNfbWxyX2ZzID0gbWFrZUZlYXRTZWxXcmFwcGVyKG9kZV9jbF9haWNfbWxyLCByZXNhbXBsaW5nID0gcmRlc2MsCmNvbnRyb2wgPSBjdHJsLCBzaG93LmluZm8gPSBGQUxTRSkKdCA8LSBtYWtlQ2xhc3NpZlRhc2soaWQgPSAic3RtX2RhdGFfc3ViIiwgZGF0YSA9IHN0bV9kYXRhX3N1YiwKdGFyZ2V0ID0gJ2xjJywgZml4dXAuZGF0YSA9ICJubyIsIGNoZWNrLmRhdGEgPSBGQUxTRSkKCnN1cHByZXNzV2FybmluZ3MoUk5HdmVyc2lvbigiMy41LjAiKSkKc2V0LnNlZWQoMCkKIyBTZWxlY3QgZmVhdHVyZXMKbW9kIDwtIHRyYWluKG9kZV9jbF9haWNfbWxyX2ZzLCB0YXNrID0gdCkKc2ZlYXRzIDwtIGdldEZlYXRTZWxSZXN1bHQobW9kKQpzZmVhdHMKCmBgYAoKCiMgUGl4ZWwgL0luZGV4IFZhbHVlIERlc2NyaXB0aW9uCjEgTm8gQ2hhbmdlCjIgQ2hhbmdlIGZyb20gb3IgdG8gV2F0ZXIKMyBDaGFuZ2UgZnJvbSBvciB0byBhbnkgb2YgdGhlIGZvdXIgVXJiYW4gY2xhc3NlcyAob3BlbiBzcGFjZTsgbG93LCBtZWRpdW0sIGFuZCBoaWdoIGludGVuc2l0eSkKNCBDaGFuZ2UgZnJvbSBIZXJiYWNlb3VzIFdldGxhbmQgdG8gV29vZHkgV2V0bGFuZCwgb3IgdmljZSB2ZXJzYQo1IENoYW5nZSBmcm9tIG9yIHRvIEhlcmJhY2VvdXMgV2V0bGFuZAo2IENoYW5nZSBmcm9tIEN1bHRpdmF0ZWQgQ3JvcHMgdG8gSGF5IC8gUGFzdHVyZSwgb3IgdmljZSB2ZXJzYQo3IENoYW5nZSBmcm9tIG9yIHRvIEN1bHRpdmF0ZWQgQ3JvcHMKOCBDaGFuZ2UgZnJvbSBvciB0byBIYXkgLyBQYXN0dXJlCjkgUGVyc2lzdGVudCBHcmFzc2xhbmQgYW5kIFNocnVibGFuZCBjaGFuZ2UuIFRoaXMgY2hhbmdlIGluZGV4IGF0dGVtcHRzIHRvIGlkZW50aWZ5IGNoYW5nZXMgdG8gcGVyc2lzdGVudCBHcmFzc2xhbmQgYW5kIFNocnVibGFuZCBhcmVhcywgYW5kIHRvIHNlcGFyYXRlIHRoZW0gZnJvbSB0cmFuc2l0aW9uYWwgc2hydWJsYW5kIGFyZWFzIHN1Y2ggYXMgcmVnZW5lcmF0aW5nIGZvcmVzdHMuCjEwIENoYW5nZSBmcm9tIG9yIHRvIEJhcnJlbgoxMSBDaGFuZ2UgZnJvbSBvciB0byBhbnkgb2YgdGhlIHRocmVlIEZvcmVzdCBjbGFzc2VzIChFdmVyZ3JlZW4sIERlY2lkdW91cywgYW5kIE1peGVkKQoxMiBDaGFuZ2UgZnJvbSBvciB0byBXb29keSBXZXRsYW5kCgoKIyBOYXRpb25hbCBMYW5kIENvdmVyIERhdGFiYXNlIENsYXNzIExlZ2VuZCBhbmQgRGVzY3JpcHRpb24KQ2xhc3NcIFZhbHVlIENsYXNzaWZpY2F0aW9uIERlc2NyaXB0aW9uCgojIyBXYXRlcgoxMSBPcGVuIFdhdGVyLSBhcmVhcyBvZiBvcGVuIHdhdGVyLCBnZW5lcmFsbHkgd2l0aCBsZXNzIHRoYW4gMjUlIGNvdmVyIG9mIHZlZ2V0YXRpb24Kb3Igc29pbC4KCjEyIFBlcmVubmlhbCBJY2UvU25vdy0gYXJlYXMgY2hhcmFjdGVyaXplZCBieSBhIHBlcmVubmlhbCBjb3ZlciBvZiBpY2UgYW5kL29yIHNub3csCmdlbmVyYWxseSBncmVhdGVyIHRoYW4gMjUlIG9mIHRvdGFsIGNvdmVyLgoKIyMgRGV2ZWxvcGVkCjIxIERldmVsb3BlZCwgT3BlbiBTcGFjZS0gYXJlYXMgd2l0aCBhIG1peHR1cmUgb2Ygc29tZSBjb25zdHJ1Y3RlZCBtYXRlcmlhbHMsIGJ1dAptb3N0bHkgdmVnZXRhdGlvbiBpbiB0aGUgZm9ybSBvZiBsYXduIGdyYXNzZXMuIEltcGVydmlvdXMgc3VyZmFjZXMgYWNjb3VudCBmb3IgbGVzcwp0aGFuIDIwJSBvZiB0b3RhbCBjb3Zlci4gVGhlc2UgYXJlYXMgbW9zdCBjb21tb25seSBpbmNsdWRlIGxhcmdlLWxvdCBzaW5nbGUtZmFtaWx5CmhvdXNpbmcgdW5pdHMsIHBhcmtzLCBnb2xmIGNvdXJzZXMsIGFuZCB2ZWdldGF0aW9uIHBsYW50ZWQgaW4gZGV2ZWxvcGVkIHNldHRpbmdzIGZvcgpyZWNyZWF0aW9uLCBlcm9zaW9uIGNvbnRyb2wsIG9yIGFlc3RoZXRpYyBwdXJwb3Nlcy4KCjIyIERldmVsb3BlZCwgTG93IEludGVuc2l0eS0gYXJlYXMgd2l0aCBhIG1peHR1cmUgb2YgY29uc3RydWN0ZWQgbWF0ZXJpYWxzIGFuZAp2ZWdldGF0aW9uLiBJbXBlcnZpb3VzIHN1cmZhY2VzIGFjY291bnQgZm9yIDIwJSB0byA0OSUgcGVyY2VudCBvZiB0b3RhbCBjb3Zlci4KVGhlc2UgYXJlYXMgbW9zdCBjb21tb25seSBpbmNsdWRlIHNpbmdsZS1mYW1pbHkgaG91c2luZyB1bml0cy4KCjIzIERldmVsb3BlZCwgTWVkaXVtIEludGVuc2l0eSAtYXJlYXMgd2l0aCBhIG1peHR1cmUgb2YgY29uc3RydWN0ZWQgbWF0ZXJpYWxzIGFuZAp2ZWdldGF0aW9uLiBJbXBlcnZpb3VzIHN1cmZhY2VzIGFjY291bnQgZm9yIDUwJSB0byA3OSUgb2YgdGhlIHRvdGFsIGNvdmVyLiBUaGVzZQphcmVhcyBtb3N0IGNvbW1vbmx5IGluY2x1ZGUgc2luZ2xlLWZhbWlseSBob3VzaW5nIHVuaXRzLgoKMjQgRGV2ZWxvcGVkIEhpZ2ggSW50ZW5zaXR5LWhpZ2hseSBkZXZlbG9wZWQgYXJlYXMgd2hlcmUgcGVvcGxlIHJlc2lkZSBvciB3b3JrIGluCmhpZ2ggbnVtYmVycy4gRXhhbXBsZXMgaW5jbHVkZSBhcGFydG1lbnQgY29tcGxleGVzLCByb3cgaG91c2VzIGFuZApjb21tZXJjaWFsL2luZHVzdHJpYWwuIEltcGVydmlvdXMgc3VyZmFjZXMgYWNjb3VudCBmb3IgODAlIHRvIDEwMCUgb2YgdGhlIHRvdGFsCmNvdmVyLgoKIyMgQmFycmVuCjMxIEJhcnJlbiBMYW5kIChSb2NrL1NhbmQvQ2xheSkgLSBhcmVhcyBvZiBiZWRyb2NrLCBkZXNlcnQgcGF2ZW1lbnQsIHNjYXJwcywgdGFsdXMsCnNsaWRlcywgdm9sY2FuaWMgbWF0ZXJpYWwsIGdsYWNpYWwgZGVicmlzLCBzYW5kIGR1bmVzLCBzdHJpcCBtaW5lcywgZ3JhdmVsIHBpdHMgYW5kIG90aGVyCmFjY3VtdWxhdGlvbnMgb2YgZWFydGhlbiBtYXRlcmlhbC4gR2VuZXJhbGx5LCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBsZXNzIHRoYW4gMTUlCm9mIHRvdGFsIGNvdmVyLgoKIyMgRm9yZXN0CjQxIERlY2lkdW91cyBGb3Jlc3QtIGFyZWFzIGRvbWluYXRlZCBieSB0cmVlcyBnZW5lcmFsbHkgZ3JlYXRlciB0aGFuIDUgbWV0ZXJzIHRhbGwsCmFuZCBncmVhdGVyIHRoYW4gMjAlIG9mIHRvdGFsIHZlZ2V0YXRpb24gY292ZXIuIE1vcmUgdGhhbiA3NSUgb2YgdGhlIHRyZWUgc3BlY2llcwpzaGVkIGZvbGlhZ2Ugc2ltdWx0YW5lb3VzbHkgaW4gcmVzcG9uc2UgdG8gc2Vhc29uYWwgY2hhbmdlLgoKNDIgRXZlcmdyZWVuIEZvcmVzdC0gYXJlYXMgZG9taW5hdGVkIGJ5IHRyZWVzIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gNSBtZXRlcnMgdGFsbCwKYW5kIGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbiBjb3Zlci4gTW9yZSB0aGFuIDc1JSBvZiB0aGUgdHJlZSBzcGVjaWVzCm1haW50YWluIHRoZWlyIGxlYXZlcyBhbGwgeWVhci4gQ2Fub3B5IGlzIG5ldmVyIHdpdGhvdXQgZ3JlZW4gZm9saWFnZS4KCjQzIE1peGVkIEZvcmVzdC0gYXJlYXMgZG9taW5hdGVkIGJ5IHRyZWVzIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gNSBtZXRlcnMgdGFsbCwgYW5kCmdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbiBjb3Zlci4gTmVpdGhlciBkZWNpZHVvdXMgbm9yIGV2ZXJncmVlbiBzcGVjaWVzCmFyZSBncmVhdGVyIHRoYW4gNzUlIG9mIHRvdGFsIHRyZWUgY292ZXIuCgojIyBTaHJ1YmxhbmQKNTEgRHdhcmYgU2NydWItIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBzaHJ1YnMgbGVzcyB0aGFuIDIwIGNlbnRpbWV0ZXJzIHRhbGwKd2l0aCBzaHJ1YiBjYW5vcHkgdHlwaWNhbGx5IGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhpcyB0eXBlIGlzIG9mdGVuCmNvLWFzc29jaWF0ZWQgd2l0aCBncmFzc2VzLCBzZWRnZXMsIGhlcmJzLCBhbmQgbm9uLXZhc2N1bGFyIHZlZ2V0YXRpb24uCgo1MiBTaHJ1Yi9TY3J1Yi0gYXJlYXMgZG9taW5hdGVkIGJ5IHNocnViczsgbGVzcyB0aGFuIDUgbWV0ZXJzIHRhbGwgd2l0aCBzaHJ1YiBjYW5vcHkKdHlwaWNhbGx5IGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhpcyBjbGFzcyBpbmNsdWRlcyB0cnVlIHNocnVicywgeW91bmcKdHJlZXMgaW4gYW4gZWFybHkgc3VjY2Vzc2lvbmFsIHN0YWdlIG9yIHRyZWVzIHN0dW50ZWQgZnJvbSBlbnZpcm9ubWVudGFsIGNvbmRpdGlvbnMuCgojIyBIZXJiYWNlb3VzCjcxIEdyYXNzbGFuZC9IZXJiYWNlb3VzLSBhcmVhcyBkb21pbmF0ZWQgYnkgZ3JhbWFub2lkIG9yIGhlcmJhY2VvdXMgdmVnZXRhdGlvbiwKZ2VuZXJhbGx5IGdyZWF0ZXIgdGhhbiA4MCUgb2YgdG90YWwgdmVnZXRhdGlvbi4gVGhlc2UgYXJlYXMgYXJlIG5vdCBzdWJqZWN0IHRvCmludGVuc2l2ZSBtYW5hZ2VtZW50IHN1Y2ggYXMgdGlsbGluZywgYnV0IGNhbiBiZSB1dGlsaXplZCBmb3IgZ3JhemluZy4KCjcyIFNlZGdlL0hlcmJhY2VvdXMtIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBzZWRnZXMgYW5kIGZvcmJzLCBnZW5lcmFsbHkKZ3JlYXRlciB0aGFuIDgwJSBvZiB0b3RhbCB2ZWdldGF0aW9uLiBUaGlzIHR5cGUgY2FuIG9jY3VyIHdpdGggc2lnbmlmaWNhbnQgb3RoZXIKZ3Jhc3NlcyBvciBvdGhlciBncmFzcyBsaWtlIHBsYW50cywgYW5kIGluY2x1ZGVzIHNlZGdlIHR1bmRyYSwgYW5kIHNlZGdlIHR1c3NvY2sKdHVuZHJhLgoKNzMgTGljaGVucy0gQWxhc2thIG9ubHkgYXJlYXMgZG9taW5hdGVkIGJ5IGZydXRpY29zZSBvciBmb2xpb3NlIGxpY2hlbnMgZ2VuZXJhbGx5CmdyZWF0ZXIgdGhhbiA4MCUgb2YgdG90YWwgdmVnZXRhdGlvbi4KCjc0IE1vc3MtIEFsYXNrYSBvbmx5IGFyZWFzIGRvbWluYXRlZCBieSBtb3NzZXMsIGdlbmVyYWxseSBncmVhdGVyIHRoYW4gODAlIG9mIHRvdGFsCnZlZ2V0YXRpb24uCgojIyBQbGFudGVkL0N1bHRpdmF0ZWQKODEgUGFzdHVyZS9IYXktYXJlYXMgb2YgZ3Jhc3NlcywgbGVndW1lcywgb3IgZ3Jhc3MtbGVndW1lIG1peHR1cmVzIHBsYW50ZWQgZm9yCmxpdmVzdG9jayBncmF6aW5nIG9yIHRoZSBwcm9kdWN0aW9uIG9mIHNlZWQgb3IgaGF5IGNyb3BzLCB0eXBpY2FsbHkgb24gYSBwZXJlbm5pYWwKY3ljbGUuIFBhc3R1cmUvaGF5IHZlZ2V0YXRpb24gYWNjb3VudHMgZm9yIGdyZWF0ZXIgdGhhbiAyMCUgb2YgdG90YWwgdmVnZXRhdGlvbi4KCjgyIEN1bHRpdmF0ZWQgQ3JvcHMgLWFyZWFzIHVzZWQgZm9yIHRoZSBwcm9kdWN0aW9uIG9mIGFubnVhbCBjcm9wcywgc3VjaCBhcyBjb3JuLApzb3liZWFucywgdmVnZXRhYmxlcywgdG9iYWNjbywgYW5kIGNvdHRvbiwgYW5kIGFsc28gcGVyZW5uaWFsIHdvb2R5IGNyb3BzIHN1Y2ggYXMKb3JjaGFyZHMgYW5kIHZpbmV5YXJkcy4gQ3JvcCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBncmVhdGVyIHRoYW4gMjAlIG9mIHRvdGFsCnZlZ2V0YXRpb24uIFRoaXMgY2xhc3MgYWxzbyBpbmNsdWRlcyBhbGwgbGFuZCBiZWluZyBhY3RpdmVseSB0aWxsZWQuCgojIyBXZXRsYW5kcwo5MCBXb29keSBXZXRsYW5kcy0gYXJlYXMgd2hlcmUgZm9yZXN0IG9yIHNocnVibGFuZCB2ZWdldGF0aW9uIGFjY291bnRzIGZvciBncmVhdGVyCnRoYW4gMjAlIG9mIHZlZ2V0YXRpdmUgY292ZXIgYW5kIHRoZSBzb2lsIG9yIHN1YnN0cmF0ZSBpcyBwZXJpb2RpY2FsbHkgc2F0dXJhdGVkIHdpdGgKb3IgY292ZXJlZCB3aXRoIHdhdGVyLgoKCiMgRGVub21pbmF0aW9uIHBoIHJhbmdlClVsdHJhIGFjaWQgPCAzLjUKRXh0cmVtZWx5IGFjaWQgMy414oCTNC40ClZlcnkgc3Ryb25nbHkgYWNpZCA0LjXigJM1LjAKU3Ryb25nbHkgYWNpZCA1LjHigJM1LjUKTW9kZXJhdGVseSBhY2lkIDUuNuKAkzYuMApTbGlnaHRseSBhY2lkIDYuMeKAkzYuNQpOZXV0cmFsIDYuNuKAkzcuMwpTbGlnaHRseSBhbGthbGluZSA3LjTigJM3LjgKTW9kZXJhdGVseSBhbGthbGluZSA3LjnigJM4LjQKU3Ryb25nbHkgYWxrYWxpbmUgOC414oCTOS4wClZlcnkgc3Ryb25nbHkgYWxrYWxpbmUgPiA5LjAKCgoKIyBTT0MgY2xhc3NlcyAoNCBjbGFzc2VzKQo8IS0tIDAtMSAtLT4KPCEtLSAxLTIgLS0+CjwhLS0gMi0zIC0tPgo8IS0tID4zIC0tPgoKCgojIERiIGNsYXNzZXMKPCEtLSA8MSA9IHZlcnkgbG9vc2UgLS0+CjwhLS0gMS0xLjIgPSBsb29zZSAtLT4KPCEtLSAxLjItMS40ID0gbm9ybWFsIC0tPgo8IS0tIDEuNC0xLjYgPSBoYXJkIC0tPgo8IS0tID4xLjYgPSBjb21wYWN0IC0tPgoKCgpgYGB7cn0KdGV4dHVyZXMgPC0gYygiU2FuZCIsIkxvYW15IHNhbmQiLCJTYW5keSBsb2FtIiwiTG9hbSIsIlNpbHQgbG9hbSIsCiAgICAgICAgICAgICAgICAiU2lsdCIsIlNhbmR5IGNsYXkgbG9hbSIsIkNsYXkgbG9hbSIsIlNpbHR5IGNsYXkgbG9hbSIsCiAgICAgICAgICAgICAgICAiU2FuZHkgY2xheSIsIlNpbHR5IGNsYXkiLCJDbGF5IikKCnBoX2NsYXNzIDwtIGZ1bmN0aW9uKHBoKXsKaWYoaXMubmEocGgpKXsKICBjbGFzcyA9IE5BCn1lbHNlIGlmKHBoIDw9IDMuNSl7CiAgY2xhc3MgPSAnVWx0cmEgYWNpZCcKfWVsc2UgaWYocGggPiAzLjUgJiBwaCA8PSA0LjUpewogIGNsYXNzID0gJ0V4dHJlbWVseSBhY2lkJwp9ZWxzZSBpZihwaCA+IDQuNSAmIHBoIDw9IDUpewogIGNsYXNzID0gJ1Zlcnkgc3Ryb25nbHkgYWNpZCcKfWVsc2UgaWYocGggPiA1ICYgcGggPCA1LjYpewogIGNsYXNzID0gJ1N0cm9uZ2x5IGFjaWQnCn1lbHNlIGlmKHBoID49IDUuNiAmIHBoIDw9IDYpewogIGNsYXNzID0gJ01vZGVyYXRlbHkgYWNpZCcKfWVsc2UgaWYocGggPiA2ICYgcGggPD0gNi41KXsKICBjbGFzcyA9ICdTbGlnaHRseSBhY2lkJwp9ZWxzZSBpZihwaCA+IDYuNSAmIHBoIDw9IDcuMyl7CiAgY2xhc3MgPSAnTmV1dHJhbCcKfWVsc2UgaWYocGggPiA3LjMgJiBwaCA8PSA3LjgpewogIGNsYXNzID0gJ1NsaWdodGx5IGFsa2FsaW5lJwp9ZWxzZSBpZihwaCA+IDcuOCAmIHBoIDw9IDguNCl7CiAgY2xhc3MgPSAnTW9kZXJhdGVseSBhbGthbGluZScKfWVsc2UgaWYocGggPiA4LjQgJiBwaCA8PSA5KXsKICBjbGFzcyA9ICdTdHJvbmdseSBhbGthbGluZScKfWVsc2UgaWYocGggPiA5ICYgcGggPD0gOSl7CiAgY2xhc3MgPSAnVmVyeSBzdHJvbmdseSBhbGthbGluZScKfWVsc2Uge2NsYXNzID0gTkF9CnJldHVybihjbGFzcykKfQoKc29jX2NsYXNzIDwtIGZ1bmN0aW9uKHNvYyl7CmlmKGlzLm5hKHNvYykpewogIGNsYXNzID0gTkEKfWVsc2UgaWYoc29jIDw9IDEpewogIGNsYXNzID0gJ2xvdycKfWVsc2UgaWYoc29jID4gMSAmIHNvYyA8PSAyKXsKICBjbGFzcyA9ICdtb2RlcmF0ZScKfWVsc2UgaWYoc29jID4gMiAmIHNvYyA8PSAzKXsKICBjbGFzcyA9ICdoaWdoJwp9ZWxzZSBpZihzb2MgPiAzKXsKICBjbGFzcyA9ICd2ZXJ5IGhpZ2gnCn1lbHNlIHtjbGFzcyA9IE5BfQpyZXR1cm4oY2xhc3MpCn0KCmRiX2NsYXNzIDwtIGZ1bmN0aW9uKERiKXsKaWYoaXMubmEoRGIpKXsKICBjbGFzcyA9IE5BCn1lbHNlIGlmKERiIDw9IDEpewogIGNsYXNzID0gJ3ZlcnkgbG9vc2UnCn1lbHNlIGlmKERiID4gMSAmIERiIDw9IDEuMil7CiAgY2xhc3MgPSAnbG9vc2UnCn1lbHNlIGlmKERiID4gMS4yICYgRGIgPD0gMS40KXsKICBjbGFzcyA9ICdub3JtYWwnCn1lbHNlIGlmKERiID4gMS40ICYgRGIgPD0gMS42KXsKICBjbGFzcyA9ICdoYXJkJwp9ZWxzZSBpZihEYiA+IDEuNil7CiAgY2xhc3MgPSAnY29tcGFjdCcKfQpyZXR1cm4oY2xhc3MpCn0KCmdldHR0IDwtIGZ1bmN0aW9uKHNhbmQsIHNpbHQsIGNsYXkpewogIGlmKGlzLm5hKHNhbmQpIHwgaXMubmEoc2lsdCkgfCBpcy5uYShjbGF5KSl7CiAgICB4ID0gTkEKICB9IGVsc2UgaWYoKHNpbHQgKyAxLjUgKiBjbGF5KSA8IDE1KXsKICAgIHggPSAiU2FuZCIKICB9IGVsc2UgaWYoKHNpbHQgKyAxLjUgKiBjbGF5KSA+PSAxNSAmIChzaWx0ICsgMi4wICogY2xheSkgPCAzMCl7CiAgICB4ID0gIkxvYW15IHNhbmQiCiAgfSBlbHNlIGlmKChjbGF5ID49IDcpICYgKGNsYXkgPD0gMjApICYgKHNhbmQgPiA1MikgJiAoKHNpbHQgKyAyLjAgKiBjbGF5KSA+PSAzMCkpewogICAgeCA9ICJTYW5keSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA8IDcpICYgKHNpbHQgPCA1MCkgJiAoKHNpbHQgKyAyLjAgKiBjbGF5KSA+PSAzMCkpewogICAgeCA9ICJTYW5keSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA+PSA3KSAmIChjbGF5IDw9IDI3KSAmIChzaWx0ID49IDI4KSAmIChzaWx0IDwgNTApICYgKHNhbmQgPD0gNTIpKXsKICAgIHggPSAiTG9hbSIKICB9IGVsc2UgaWYoKChzaWx0ID49IDUwKSAmIChjbGF5ID49IDEyKSAmIChjbGF5IDwgMjcpKSB8ICgoc2lsdCA+PSA1MCkgJiAoc2lsdCA8IDgwKSAmIChjbGF5IDwgMTIpKSl7CiAgICB4ID0gIlNpbHQgbG9hbSIKICB9IGVsc2UgaWYoKHNpbHQgPj0gODApICYgKGNsYXkgPCAxMikpewogICAgeCA9ICJTaWx0IgogIH0gZWxzZSBpZigoY2xheSA+PSAyMCkgJiAoY2xheSA8IDM1KSAmIChzaWx0IDwgMjgpICYgKHNhbmQgPiA0NSkpewogICAgeCA9ICJTYW5keSBjbGF5IGxvYW0iCiAgfSBlbHNlIGlmKChjbGF5ID49IDI3KSAmIChjbGF5IDwgNDApICYgKHNhbmQgPiAyMCkgJiAoc2FuZCA8PSA0NSkpewogICAgeCA9ICJDbGF5IGxvYW0iCiAgfSBlbHNlIGlmKChjbGF5ID49IDI3KSAmIChjbGF5IDwgNDApICYgKHNhbmQgPD0gMjApKXsKICAgIHggPSAiU2lsdHkgY2xheSBsb2FtIgogIH0gZWxzZSBpZigoY2xheSA+PSAzNSkgJiAoc2FuZCA+PSA0NSkpewogICAgeCA9ICJTYW5keSBjbGF5IgogIH0gZWxzZSBpZigoY2xheSA+PSA0MCkgJiAoc2lsdCA+PSA0MCkpewogICAgeCA9ICJTaWx0eSBjbGF5IgogIH0gZWxzZSBpZigoY2xheSA+PSA0MCkgJiAoc2FuZCA8PSA0NSkgJiAoc2lsdCA8IDQwKSl7CiAgICB4ID0gIkNsYXkiCiAgfQogIHJldHVybih4KQp9CgpgYGAKCg==